﻿using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization;
using SignalRApplication.Contracts;

namespace PoemGame.SignalR.Backend
{
    /// <summary>
    /// 游戏列表页面有可以参加的游戏，自己可以创建游戏，游戏创建完成，直接进入游戏，等待其它玩家加入，
    /// 如果没有玩家加入，可以退出，这时，退出后，游戏会被删除，如果有其它玩家加入，创建者不能退出
    /// 加入游戏也是直接进入游戏，进入游戏后，可以退出，退出后，返回游戏列表
    /// 如果有玩家加入，游戏创建者可以开始游戏，游戏开始后，玩家如果退出，则认为是出局，需要扣分
    /// 
    /// </summary>
    public class SingleGameHub : Hub
    {
        private IServiceScopeFactory serviceProviderFactory;

        protected readonly ISignalRAppService _gameAppService;

        protected static readonly Dictionary<string, MyTimer> _gameTimers = new Dictionary<string, MyTimer>();


        public SingleGameHub(ISignalRAppService gameAppService, IServiceScopeFactory serviceProviderFactory)
        {
            _gameAppService = gameAppService;
            this.serviceProviderFactory = serviceProviderFactory;
        }

        [Authorize]
        public async Task CheckUser(string user)
        {
            var isPlayer = await _gameAppService.CheckPlayer(user);

            if (isPlayer) await Clients.Caller.SendAsync("PlayerExist", user);
            else await Clients.Caller.SendAsync("PlayerNotExist", user);
        }

        [Authorize]
        public async Task AddPlayer(string playername, string nickname)
        {
            var id = await _gameAppService.AddPlayer(playername, nickname);

            await Clients.Caller.SendAsync("PlayerAdded");
        }


        /// <summary>
        /// 创建游戏，创建完成后进入游戏
        /// </summary>
        /// <param name="user"></param>
        /// <param name="description"></param>
        /// <param name="mainType"></param>
        /// <param name="playtype"></param>
        /// <param name="contextString"></param>
        /// <returns></returns>
        [Authorize]
        public async Task AddNewGame(string user, string description, string mainType, string playtype, string contextString)
        {
            try
            {
                var game = await _gameAppService.CreateGame(user, description, mainType, "", playtype == "inturn", contextString);
                //刷新用户游戏列表
                //await GetGames();
                await Clients.All.SendAsync("RefreshGames");
                //创建者进入游戏
                await Clients.Caller.SendAsync("EnterGame", game.Id);
            }
            catch (Exception ex)
            {
                await Clients.Caller.SendAsync("Error", ex.Message);
                //throw;
            }

        }

        /// <summary>
        /// 加入并进入游戏
        /// </summary>
        /// <param name="user"></param>
        /// <param name="gameId"></param>
        /// <returns></returns>
        [Authorize]
        public async Task JoinGame(string user, string gameId)
        {
            var Result = await _gameAppService.JoinGame(user, Guid.Parse(gameId));

            await Clients.Caller.SendAsync("EnterGame", gameId);
            await Clients.Group(gameId).SendAsync("ShowMessage", $"{user}加入游戏");
        }

        /// <summary>
        /// 离开游戏
        /// 如果游戏没有开始：创建者，如果已经有玩家，提示不能离开，如果没有玩家，删除游戏并返回。非创建者，离开游戏并返回
        /// 如果游戏已经开始：玩家离开游戏
        /// </summary>
        /// <param name="user"></param>
        /// <param name="gameid"></param>
        /// <returns></returns>
        [Authorize]
        public async Task LeaveGame(string user, string gameid)
        {
            var game = await _gameAppService.GetGame(Guid.Parse(gameid));
            if (game.Status == 0)
            {
                var creater = game.Creator;
                if (creater == user)
                {
                    //创建者
                    var players = game.ActivatePlayers;
                    if (players.Count() > 1)
                    {
                        await Clients.Caller.SendAsync("ShowMessage", "已经有参与的玩家，不能退出");
                    }
                    else
                    {
                        //删除
                        await _gameAppService.RemoveGame(game.Id);
                        await Clients.Caller.SendAsync("OnExitGame");
                        await Clients.All.SendAsync("RefreshGames");
                        //await GetGames();
                    }
                }
                else
                {
                    await _gameAppService.LeaveGame(user, Guid.Parse(gameid));
                    await Clients.Caller.SendAsync("OnExitGame");
                    await Clients.Group(gameid).SendAsync("ShowMessage", $"{user}退出游戏");

                }
            }
            else if (game.Status == 1)
            {
                //这时退出，按出局处理
                await _gameAppService.SetPlayerOut(user, game.Id);
                await ShowGameBack(gameid, $"{user}退出游戏");
                //await Clients.Group(gameid).SendAsync("ShowMessage", $"{user}退出游戏");
                await Clients.Caller.SendAsync("OnExitGame");
            }
            else
            {
                await Clients.Caller.SendAsync("OnExitGame");
            }
        }

        [Authorize]
        public async Task StartGame(string user, string gameId)
        {
            var Result = await _gameAppService.StartGame(user, Guid.Parse(gameId));
            await ShowGameBack(gameId, "");
        }

        [Authorize]
        public async Task GetGames(string user)
        {
            var games = await _gameAppService.GetCanPlayGames(user);

            await Clients.Caller.SendAsync("ShowGames", games);
        }

        [Authorize]
        public async Task EnterGame(string user, string gameguid)
        {
            //增加group
            await Groups.AddToGroupAsync(Context.ConnectionId, gameguid);
            await ShowGameBack(gameguid, $"{user}进入游戏");
        }

        [Authorize]
        public async Task PlayGame(string user, string gameguid, string answer)
        {
            var Result = await _gameAppService.PlayGame(user, Guid.Parse(gameguid), answer);
            await ShowGameBack(gameguid, Result);
            if (_gameTimers.ContainsKey(gameguid))
            {

                var timer = _gameTimers[gameguid];
                timer.StopTimer();
            }
        }

        [Authorize]
        public async Task StartGoToPlayTimer(string gameguid)
        {
            await Clients.Group(gameguid).SendAsync("ShowMessage", "抢答开始");

            if (!_gameTimers.ContainsKey(gameguid))
            {

                var timer = new MyTimer(Clients, gameguid, serviceProviderFactory);
                _gameTimers.Add(gameguid, timer);
                timer.StartGoToPlayTimer();
            }
            else
            {
                var timer = _gameTimers[gameguid];
                timer.StartGoToPlayTimer();
            }
        }
        [Authorize]
        public async Task SetPlayer(string user, string gameguid)
        {
            try
            {
                if (_gameTimers.ContainsKey(gameguid))
                {
                    var timer = _gameTimers[gameguid];
                    timer.StopTimer();
                }

                var Result = await _gameAppService.SetAnswerPlayer(user, Guid.Parse(gameguid));
                //var nextuser = await _gameAppService.GetGameCurrentPlayer(Guid.Parse(gameguid));
                var game = await _gameAppService.GetGame(Guid.Parse(gameguid));
                await Clients.Group(gameguid).SendAsync("SetPlayerResult", game.CurrentPlayer, Result);

                //设置超时
                if (!_gameTimers.ContainsKey(gameguid))
                {
                    var timer = new MyTimer(Clients, gameguid, serviceProviderFactory);
                    _gameTimers.Add(gameguid, timer);
                    timer.StartPlayTimer(user);
                }
                else
                {
                    var timer = _gameTimers[gameguid];
                    timer.StartPlayTimer(user);
                }
            }
            catch (Exception ex)
            {
                await Clients.Caller.SendAsync("Error", ex.Message);
                //throw;
            }
        }


        [Authorize]
        public async Task ShowGame(string user, string gameguid)
        {
            //增加group
            await Groups.AddToGroupAsync(Context.ConnectionId, gameguid);
            await ShowGameBack(user, gameguid);
        }


        protected async Task ShowGameBack(string gameguid, string message)
        {
            var game = await _gameAppService.GetGame(Guid.Parse(gameguid));
            await Clients.Group(gameguid).SendAsync("ShowGameResult", game, message);
        }

    }
}
